import { useRef, useState, useCallback, forwardRef, useImperativeHandle, useEffect } from "react";
import {
    ViewerApp,
    AssetManagerPlugin,
    GBufferPlugin,
    ProgressivePlugin,
    TonemapPlugin,
    SSRPlugin,
    SSAOPlugin,
    BloomPlugin,
    GammaCorrectionPlugin,
    mobileAndTabletCheck,
} from "webgi";
import gsap from "gsap";
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { scrollAnimation } from "../lib/scroll-animation";

gsap.registerPlugin(ScrollTrigger);

const WebgiViewer = forwardRef(({ contentRef }, ref) => {

    // Webgi canvas实例
    const canvasRef = useRef(null);

    // Webgi提供的各个控制器
    const [viewerRef, setViewerRef] = useState(null);
    const [targetRef, setTargetRef] = useState(null);
    const [cameraRef, setCameraRef] = useState(null);
    const [positionRef, setPositionRef] = useState(null);

    // canvas所在的外部div实例
    const canvasContainerRef = useRef(null);

    // 是否处于预览模式
    const [previewMode, setPreviewMode] = useState(false);

    // 是否处于移动端
    const [isMobile, setIsMobile] = useState(null);

    useImperativeHandle(ref, () => ({
        // 预览事件
        triggerPreview() {
            // 设置参数、dom元素样式为预览样式
            setPreviewMode(true);
            canvasContainerRef.current.style.pointerEvents = 'all';
            contentRef.current.style.opacity = '0';

            // Webgi画面设置为预览画面
            gsap.to(positionRef, {
                x: 13.04,
                y: -2.01,
                z: 2.29,
                duration: 2,
                onUpdate: () => {
                    viewerRef.setDirty();
                    cameraRef.positionTargetUpdated(true);
                },
            });
            gsap.to(targetRef, { x: 0.11, y: 0.0, z: 0.0, duration: 2 });

            // 开启控制
            viewerRef.scene.activeCamera.setCameraOptions({ controlsEnabled: true });
        },
    }));

    // Webgi绑定gsap时间线
    const memorizedScrollAnimation = useCallback((position, target, isMobile, onUpdate) => {
        if (position && target && onUpdate) {
            scrollAnimation(position, target, isMobile, onUpdate);
        }
    });

    // 初始化Webgi
    const setupViewer = useCallback(async () => {

        // Initialize the viewer
        const viewer = new ViewerApp({ canvas: canvasRef.current });

        // 记录观察器
        setViewerRef(viewer);

        const isMobileOrTablet = mobileAndTabletCheck();
        setIsMobile(isMobileOrTablet);

        // Webgi插件管理器
        const manager = await viewer.addPlugin(AssetManagerPlugin);

        // 记录各个控制器
        const camera = viewer.scene.activeCamera;
        const position = camera.position;
        const target = camera.target;
        setCameraRef(camera);
        setPositionRef(position);
        setTargetRef(target);

        // Add plugins individually.
        await viewer.addPlugin(GBufferPlugin);
        await viewer.addPlugin(new ProgressivePlugin(32));
        await viewer.addPlugin(new TonemapPlugin(true));
        await viewer.addPlugin(GammaCorrectionPlugin);
        await viewer.addPlugin(SSRPlugin);
        await viewer.addPlugin(SSAOPlugin);
        await viewer.addPlugin(BloomPlugin);

        viewer.renderer.refreshPipeline();

        // Import and add a GLB file.
        await manager.addFromPath('scene-black.glb');

        // 使背景透明
        viewer.getPlugin(TonemapPlugin).config.clipBackground = true;

        // 禁用相机旋转
        viewer.scene.activeCamera.setCameraOptions({ controlsEnabled: false });

        // 切换为移动端视图
        if (isMobileOrTablet) {
            position.set(-16.7, 1.17, 11.7);
            target.set(0, 1.37, 0);
            contentRef.current.className = 'mobile-or-tablet';
        }

        window.scrollTo(0, 0);

        let needsUpdate = true;

        const onUpdate = () => {
            needsUpdate = true;
            viewer.setDirty();
        };

        viewer.addEventListener('preFrame', () => {
            if (needsUpdate) {
                camera.positionTargetUpdated(true);
                needsUpdate = false;
            }
        });

        memorizedScrollAnimation(position, target, isMobileOrTablet, onUpdate);

    }, []);

    useEffect(() => {
        setupViewer();
    }, []);

    const handleExit = useCallback(() => {
        canvasContainerRef.current.style.pointerEvents = 'none';
        contentRef.current.style.opacity = '1';
        viewerRef.scene.activeCamera.setCameraOptions({ controlsEnabled: false });
        setPreviewMode(false);

        gsap.to(positionRef, {
            x: !isMobile ? 1.56 : 9.36,
            y: !isMobile ? 5.0 : 10.95,
            z: !isMobile ? 0.01 : 0.09,
            scrollTrigger: {
                trigger: '.display-section',
                start: 'top bottom',
                end: 'top top',
                scrub: 2,
                immediateRender: false,
            },
            onUpdate: () => {
                viewerRef.setDirty();
                cameraRef.positionTargetUpdated(true);
            },
        }).to(targetRef, {
            x: !isMobile ? -0.55 : -1.62,
            y: !isMobile ? 0.32 : 0.02,
            z: !isMobile ? 0.0 : -0.06,
            scrollTrigger: {
                trigger: '.display-section',
                start: 'top bottom',
                end: 'top top',
                scrub: 2,
                immediateRender: false,
            },
        });
    }, [canvasContainerRef, viewerRef, positionRef, cameraRef, targetRef]);

    return (
        <div ref={canvasContainerRef} id="webgi-canvas-container">
            <canvas id="webgi-canvas" ref={canvasRef} />
            {
                previewMode && (
                    <button className="button" onClick={handleExit}>Exit</button>
                )
            }
        </div>
    );
});

export default WebgiViewer;